<template>
  <div class="navigationContainer">
    <div
      class="sm-compass"
      @mousedown="handleMouseDown"
      @dblclick="handleDBLClick"
      @mouseup="handleMouseUp"
    >
      <div class="sm-compass-tilt" />
      <div
        class="sm-compass-tiltbar"
        :style="{ top: tiltbarTop + 'px', left: tiltbarLeft + 'px' }"
      />
      <div class="sm-compass-arrows" />
      <div
        class="sm-compass-outer-ring"
        :style="{ transform: 'rotate(' + heading + 'rad)' }"
      />
      <div class="arrows_e_active" />
      <div class="arrows_n_active" />
      <div class="arrows_s_active" />
      <div class="arrows_w_active" />
    </div>
    <div class="sm-zoom">
      <div
        class="sm-zoomin"
        @mousedown="handleZoomMouseDown($event, true)" />
      <div
        class="sm-zoomout"
        @mousedown="handleZoomMouseDown($event, false)" />
      <div
        class="sm-zoombar"
        :style="{ top: scollY + 'px' }"
        @mousedown="handleZoomBarMouseDown($event)"
      />
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted, nextTick, defineExpose } from 'vue'
import dmap from '../../assets/dmap/dmap-es'

const scollY = ref(65)
const heading = ref(-6.28319)
const tiltbarTop = ref(3)
const tiltbarLeft = ref(56)
let changeY = 0
let timeOut = null
let setIntervals = null
let zoomMouseDownEvent = null
/**
 * 组件初始化
 */
const init = () => {
  window.viewer.scene.postRender.addEventListener(() => {
    if (window.viewer.scene.camera.pitch) {
      const pitch = dmap.CMap.Math.toDegrees(window.viewer.scene.camera.pitch)
      heading.value = -window.viewer.scene.camera.heading
      tiltbarTop.value = Math.ceil(
        56 - 53 * Math.cos(((90 - Math.abs(pitch)) * Math.PI) / 180)
      )
      tiltbarLeft.value = Math.ceil(
        56 + 51 * Math.sin(((90 - Math.abs(pitch)) * Math.PI) / 180)
      )
      if (tiltbarTop.value < 3) {
        tiltbarTop.value = 3
      }
      if (tiltbarLeft.value > 107) {
        tiltbarLeft.value = 107
      }
    }
  })
}

/**
 * 鼠标点击
 * @param {MouseEvent} e 事件对象
 */
const handleMouseDown = (e) => {
  pauseEvent(e)
  if (mouseInDiv('sm-compass-outer-ring', e)) {
    window.viewer.dCamera.cameraRotate.viewerRotate(e)
    return
  }
  if (mouseInDiv('sm-compass-tiltbar', e)) {
    window.viewer.dCamera.cameraRotate.viewerOrbit(e)
    return
  }
  const update = function () {
    if (mouseInDiv('arrows_w_active', e)) {
      window.viewer.dCamera.moveLeft()
    } else if (mouseInDiv('arrows_e_active', e)) {
      window.viewer.dCamera.moveRight()
    } else if (mouseInDiv('arrows_n_active', e)) {
      window.viewer.dCamera.moveUp()
    } else if (mouseInDiv('arrows_s_active', e)) {
      window.viewer.dCamera.moveDown()
    }
  }
  update()
  timeOut = setTimeout(() => {
    setIntervals = setInterval(() => {
      update()
    }, 50)
  }, 100)
}

/**
 * 双击重置视角
 * #TODO 此处缺少判断圆环操作，点击位置必须是圆环内
 */
const handleDBLClick = () => {
  window.viewer.dCamera.cameraRotate.viewerRest()
}

/**
 * 左键松开
 */
const handleMouseUp = () => {
  clearTimeout(timeOut)
  clearInterval(setIntervals)
  timeOut = null
  setIntervals = null
}

/**
 * 判断当前选中div
 */
const mouseInDiv = (div, e) => {
  const element = document.getElementsByClassName(div)[0]
  if (e.target === element) {
    return true
  }
  return false
}

/**
 * 鼠标缩放处理
 * @param {boolean} isZoom 放大:true,缩小:false
 */
const handleZoomMouseDown = (e, isZoom) => {
  pauseEvent(e)
  if (isZoom) {
    zoomIn()
  } else {
    zoomOut()
  }
  timeOut = setTimeout(() => {
    setIntervals = setInterval(() => {
      if (isZoom) {
        zoomIn()
      } else {
        zoomOut()
      }
    }, 50)
  }, 100)
}

/**
 * 暂停弹起事件
 * @param {MouseEvent} e
 */
const pauseEvent = (e) => {
  if (e.stopPropagation) e.stopPropagation()
  if (e.preventDefault) e.preventDefault()
  e.cancelBubble = true
  e.returnValue = false
}

/**
 * 鼠标缩放滑动条
 * @param {MouseEvent} e 事件对象
 */
const handleZoomBarMouseDown = (e) => {
  pauseEvent(e)
  zoomMouseDownEvent = e
  timeOut = setTimeout(() => {
    setIntervals = setInterval(() => {
      if (changeY > 0) {
        zoomOut()
      } else {
        zoomIn()
      }
    }, 50)
  }, 100)
}

/**
 * 滑动条移动
 * @param {MouseEvent} e 事件对象
 */
const handleZoomMouseMove = (e) => {
  if (zoomMouseDownEvent) {
    changeY = e.clientY - zoomMouseDownEvent.clientY
    scollY.value = 65 + changeY
    if (scollY.value > 120) {
      scollY.value = 120
    } else if (scollY.value < 0) {
      scollY.value = 0
    }
  }
}

/**
 * 点击缩放弹起
 */
const handleZoomMouseUp = () => {
  clearTimeout(timeOut)
  clearInterval(setIntervals)
  timeOut = null
  setIntervals = null
  zoomMouseDownEvent = null
  scollY.value = 65
}

/**
 * 放大
 */
const zoomIn = () => {
  if (window.viewer.dCamera.level < window.viewer.dCamera.maxLevel) {
    const { height } = window.viewer.camera.positionCartographic
    window.viewer.camera.zoomIn(height / 100)
  }
}

/**
 * 缩小
 */
const zoomOut = () => {
  if (window.viewer.dCamera.level > window.viewer.dCamera.minLevel) {
    const { height } = window.viewer.camera.positionCartographic
    window.viewer.camera.zoomOut(height / 100)
  }
}

onMounted(() => {
  nextTick(() => {
    document.addEventListener('mouseup', handleZoomMouseUp)
    document.addEventListener('mousemove', handleZoomMouseMove)
  })
})

defineExpose({init})
</script>
<style scoped>
.sm-compass {
  pointer-events: auto;
  position: absolute;
  right: 10px;
  top: 10px;
  width: 128px;
  height: 128px;
  overflow: hidden;
}
.sm-compass-outer-ring {
  cursor: pointer;
  position: absolute;
  width: 128px;
  height: 128px;
  top: 0px;
  transform: rotate(0rad);
  -webkit-transform: rotate(0rad);
  background-image: url("../../assets/images/navigation/ring.png");
}
.sm-compass-outer-ring:active {
  background-image: url("../../assets/images/navigation/ring_active.png");
}
.sm-compass-tilt {
  position: absolute;
  width: 128px;
  height: 128px;
  background-image: url("../../assets/images/navigation/tilt.png");
  visibility: hidden;
}
.navigationContainer {
  display: block;
  position: absolute;
  top: 0;
  right: 0;
  padding: 0;
  -moz-box-sizing: content-box;
  -webkit-box-sizing: content-box;
  box-sizing: content-box;
  height: 300px;
  width: 128px;
}
.navigationContainer:hover .sm-compass-tilt {
  visibility: visible;
}
.navigationContainer:active .sm-compass-tilt {
  visibility: visible;
}

.sm-compass-tiltbar {
  cursor: pointer;
  position: absolute;
  width: 16px;
  height: 16px;
  /*left: 64px;
    top: 5px;*/
  background-image: url("../../assets/images/navigation/tiltbar.png");
  background-repeat: no-repeat;
  z-index: 10;
  visibility: hidden;
}

.navigationContainer:hover .sm-compass-tiltbar {
  visibility: visible;
}

.navigationContainer:active .sm-compass-tiltbar {
  visibility: visible;
}

.sm-compass-arrows {
  position: absolute;
  width: 128px;
  height: 128px;
  top: 0px;
  background-image: url("../../assets/images/navigation/compass_active.png");
  visibility: hidden;
}

.navigationContainer:hover .sm-compass-arrows {
  visibility: visible;
}

.navigationContainer:active .sm-compass-arrows {
  visibility: visible;
}

.arrows_e_active {
  cursor: pointer;
  position: absolute;
  width: 24px;
  height: 24px;
  top: 52px;
  left: 68px;
  visibility: hidden;
}

.navigationContainer:hover .arrows_e_active {
  visibility: visible;
}

.navigationContainer:active .arrows_e_active {
  visibility: visible;
}

.arrows_e_active:active {
  background-image: url("../../assets/images/navigation/arrows_e_active.png");
}

.arrows_n_active {
  cursor: pointer;
  position: absolute;
  width: 24px;
  height: 24px;
  top: 32px;
  left: 53px;
  visibility: hidden;
}

.arrows_n_active:active {
  background-image: url("../../assets/images/navigation/arrows_n_active.png");
}

.navigationContainer:hover .arrows_n_active {
  visibility: visible;
}

.navigationContainer:active .arrows_n_active {
  visibility: visible;
}

.arrows_s_active {
  cursor: pointer;
  position: absolute;
  width: 24px;
  height: 24px;
  top: 74px;
  left: 53px;
  visibility: hidden;
}

.arrows_s_active:active {
  background-image: url("../../assets/images/navigation/arrows_s_active.png");
}

.navigationContainer:hover .arrows_s_active {
  visibility: visible;
}

.navigationContainer:active .arrows_s_active {
  visibility: visible;
}

.arrows_w_active {
  cursor: pointer;
  position: absolute;
  width: 24px;
  height: 24px;
  top: 52px;
  left: 35px;
  visibility: hidden;
}

.arrows_w_active:active {
  background-image: url("../../assets/images/navigation/arrows_w_active.png");
}

.navigationContainer:hover .arrows_w_active {
  visibility: visible;
}

.navigationContainer:active .arrows_w_active {
  visibility: visible;
}

.sm-zoom {
  position: absolute;
  width: 30px;
  height: 150px;
  background-image: url("../../assets/images/navigation/zoom.png");
  top: 130px;
  right: 60px;
  visibility: hidden;
}

.navigationContainer:hover .sm-zoom {
  visibility: visible;
}
.navigationContainer:active .sm-zoom {
  visibility: visible;
}

.sm-zoomin {
  cursor: pointer;
  position: absolute;
  width: 32px;
  height: 32px;
}
.sm-zoomin:active {
  background-image: url("../../assets/images/navigation/zoom_active_in.png");
}
.sm-zoomout {
  cursor: pointer;
  position: absolute;
  width: 32px;
  height: 32px;
  bottom: 0px;
}
.sm-zoomout:active {
  background-image: url("../../assets/images/navigation/zoom_active_out.png");
}
.sm-zoombar {
  cursor: pointer;
  position: absolute;
  width: 32px;
  height: 32px;
  top: 65px;
  background-image: url("../../assets/images/navigation/zoombar.png");
}
</style>
